﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web.Mvc;
using OpenFlashChart;
using Peak.ApplicationServices;
using Peak.ApplicationServices.Services;
using Peak.Core;
using Peak.Core.DataInterfaces;
using Peak.Web.Controllers.Models;
using Peak.Web.Controllers.Services;
using SharpArch.Data.NHibernate;
using SharpArch.Web.NHibernate;
using MvcContrib;
using Peak.Resources;
using MvcContrib.UI.InputBuilder.Helpers;

namespace Peak.Web.Controllers
{
  public class TaskController : BaseController
  {
    private readonly ITaskService _taskService;
    private readonly ISprintStoryService _sprintStoryService;

    public TaskController(ISessionService sessionService, ITaskService taskService, ISprintStoryService sprintStoryService)
      :base(sessionService)
    {
      _taskService = taskService;
      _sprintStoryService = sprintStoryService;
    }

    public ActionResult Index(int taskId)
    {
      Task task = _taskService.Get(taskId);      
      return View(new TaskModel(task));
    }

    public ActionResult New(int sprintStoryId)
    {
      return View(new TaskModel(sprintStoryId));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [ValidateInput(false)]
    [Transaction]
    public ActionResult New(TaskModel task)
    {
      if (!task.IsValid())
      {
        return View(task);
      }

      Task dbTask = new Task();      
      dbTask.Created = DateTime.Now;
      dbTask.CreatedBy = Thread.CurrentPrincipal.Identity.Name;
      SprintStory sprintStory = _sprintStoryService.Get(task.SprintStoryId);
      task.UpdateNew(dbTask, sprintStory.Story.Project.Users);              
      try
      {
        sprintStory.AddTask(dbTask);       
      }
      catch(SprintPlaningException)
      {
        ModelState.AddModelError<TaskModel>(f=>f.Status,ValidationErrors.SprintIsInPlanningState);
        NHibernateSession.Current.Transaction.Rollback();
        return View(task);
      }
      catch (NotEstimatedException)
      {
        ModelState.AddModelError<TaskModel>(f => f.RemainingEffort, ValidationErrors.NotEstimated);
        NHibernateSession.Current.Transaction.Rollback();
        return View(task);
      }

      return Back();
    }

    public ActionResult Edit(int taskId)
    {
      Task task = _taskService.Get(taskId);
      if (task == null || task.Project != _sessionService.Project)
      {
        return MessageBox(Messages.TaskNotExists);
      }
      return View(new TaskModel(task));
    }

    public ActionResult EditMany(int[] ids)
    {
      if (ids == null || ids.Length == 0)
        return MessageBox(Messages.InvalidOperation);

      if (ids.Length > 1)
        return MessageBox(Messages.MultipleEditNotSupported);

      return this.RedirectToAction(f => f.Edit(ids[0]));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [ValidateInput(false)]
    [Transaction]
    public ActionResult Edit(TaskModel task)
    {
      if (!task.IsValid())
      {
        return View(task);
      }

      Task dbTask = _taskService.Get(task.TaskId);      
      try
      {
        task.UpdateEdit(dbTask, dbTask.SprintStory.Story.Project.Users);
      }
      catch(SprintPlaningException)
      {        
        ModelState.AddModelError<TaskModel>(f=>f.Status,ValidationErrors.SprintIsInPlanningState);
        NHibernateSession.Current.Transaction.Rollback();
        return View(task);
      }
      _taskService.Update(dbTask);

      return Back();
    }

    [AcceptVerbs(HttpVerbs.Post)]    
    [Transaction]
    public ActionResult EditAssignedTo(int id, int value)
    {
      Task dbTask = _taskService.Get(id);      
      if (value != 0)
      {
        User user = dbTask.SprintStory.Story.Project.Users.First(f => f.Id == value);
        if(user == null)
        {
          return this.Content("");
        }
        dbTask.AssignedTo = user;
        if (user.UserName == Thread.CurrentPrincipal.Identity.Name)
        {
          return this.Content(Labels.Me);
        }
        else
        {
          return this.Content(user.UserName);
        }
      }
      else
      {
        dbTask.AssignedTo = null;
        return this.Content(Labels.Unassigned);
      }      
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [Transaction]
    public ActionResult EditRemainingEffort(int id, string value)                        
    {
      Task dbTask = _taskService.Get(id);      
      TimeSpan effort;
      DurationParser.SmartParse(value, out effort);
      dbTask.RemainingEffort = effort;
      return this.Content(DurationParser.ToString(effort));      
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [Transaction]
    public ActionResult EditStatus(int id, TaskStatus value)
    {
      Task dbTask = _taskService.Get(id);
      dbTask.Status = value;
      return this.Content(Resources.Statuses.ResourceManager.GetString(value.ToString()));
    }

    [Transaction]
    public ActionResult Remove(int taskId)
    {
      Task dbTask = _taskService.Get(taskId);
      dbTask.SprintStory.Story.CurrentSprintStory.RemoveTask(dbTask);
      return this.RedirectToAction<StoryController>(f => f.Index(dbTask.SprintStory.Id, null));
    }

    [Transaction]
    public ActionResult RemoveMany(int[] ids)
    {
      if (ids == null)
        return RedirectToThis();

      foreach (int id in ids)
      {
        Task dbTask = _taskService.Get(id);
        dbTask.SprintStory.Story.CurrentSprintStory.RemoveTask(dbTask);
      }
      return RedirectToThis();
    }

    [Transaction]
    public ActionResult AssignToMe(int taskId)
    {
      Task dbTask = _taskService.Get(taskId);
      dbTask.AssignedTo = _sessionService.User;
      return RedirectToThis();
    }

    [Transaction]
    public ActionResult AssignToMeMany(int[] ids)
    {
      if(ids == null)
        return RedirectToThis();

      foreach (int id in ids)
      {
        Task dbTask = _taskService.Get(id);
        dbTask.AssignedTo = _sessionService.User;
      }
      return RedirectToThis();
    }

    
    public ActionResult MoveToStory(int[] ids)
    {
      if (ids == null && ids.Length == 0)
      {
        return MessageBox(Messages.InvalidOperation);
      }

      string returnUrl = "\"~/Task.aspx/MoveToStoryOk?";
      foreach (int id in ids)
      {
        returnUrl += "ids=" + id+"&";
      }
      returnUrl += "\"";
      return ControllerExtensions2.RedirectToAction2<SelectStoriesController>(f => f.Index(null, returnUrl, false, new StoryFilterModel() { SortOrder = StorySortOrder.Name, SortDirection = SortDirection.Asc }));
    }

    [Transaction]
    public ActionResult MoveToStoryOk(int[] ids, int sprintStoryId)
    {
      if (ids == null && ids.Length == 0)
      {
        return MessageBox(Messages.InvalidOperation);
      }

      SprintStory sprintStory = _sprintStoryService.Get(sprintStoryId);

      foreach (int id in ids)
      {
        Task task = _taskService.Get(id);
        if (task.Project != _sessionService.Project)
          return MessageBox(Messages.InvalidOperation);
        task.SprintStory.Story.CurrentSprintStory.RemoveTask(task);
        sprintStory.AddTask(task);
      }
      return this.RedirectToAction<StoryController>(f => f.Index(sprintStory.Id,null));
    }
  }
}
